package com.imcreator.icchat.ServerThreads;

import java.io.BufferedReader;
import java.io.IOException;
import java.net.Socket;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import org.jline.utils.InputStreamReader;

import com.imcreator.icchat.Colors;
import com.imcreator.icchat.IcChat;
import com.imcreator.icchat.Methods;
import com.imcreator.icchat.Objects.Client;

import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

public class ClientThread extends Thread {
    public Socket socket;
    private String name = null;
    private Integer pwdTimes = 3;
    public Boolean connecting = true;
    public BufferedReader bufferedReader = null;

    public ClientThread(Socket socket) {
        this.socket = socket;
    }

    public void run() {
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
            this.bufferedReader = bufferedReader;
            while (connecting) {
                if (socket.isClosed()) {
                    Methods.printAbove(Methods.changeColor(
                        "与" + name + "客户端(" + socket.getInetAddress() + ")的Socket连接意外中断", 
                        Colors.RED_BOLD));
                    connecting = false;
                    continue;
                }

                String messString = bufferedReader.readLine();
                if (messString == null) {
                    continue;
                }
                JSONObject jsonObject = JSONUtil.parseObj(messString);
                String type = jsonObject.getStr("type");
                String content = jsonObject.getStr("content");
                switch (type.toLowerCase()) {
                    case "user-name":
                        if (!IcChat.clientsMap.containsKey(content)) { // 记录客户端用户名
                            name = content;
                            if (IcChat.password.isEmpty()) { // 无密码时放入键值对
                                Client client = new Client(socket, name, this);
                                IcChat.verifingList.remove(this);
                                IcChat.clientsMap.put(name, client);
                                IcChat.dynamicCompleter.setNameList(IcChat.clientsMap.keySet()); // 更新Tab列表
                                Methods.sendMessage(socket, "info", "verified");
                                Methods.sendMessage(
                                    socket, 
                                    "onlineList", 
                                    IcChat.clientsMap.keySet().stream().collect(Collectors.joining(","))); // 给客户端发送tab列表
                                Methods.printAbove(Methods.changeColor(
                                    name + "客户端(" + socket.getInetAddress() + ")验证通过", 
                                    Colors.GREEN_BOLD));
                            } else {
                                Methods.sendMessage(socket, "require", "password");
                            }
                        } else { // 已有同名用户处理
                            Methods.sendMessage(socket, "error", "name");
                            connecting = false;
                        }
                        break;
                    case "password":
                        if (content.equals(IcChat.password)) {
                            if (!IcChat.clientsMap.containsKey(name)) { // 密码正确时放入键值对
                                Client client = new Client(socket, name, this);
                                IcChat.verifingList.remove(this);
                                IcChat.clientsMap.put(name, client);
                                IcChat.dynamicCompleter.setNameList(IcChat.clientsMap.keySet()); // 更新Tab列表
                                Methods.sendMessage(socket, "info", "verified");
                                Methods.sendMessage(
                                    socket, 
                                    "onlineList", 
                                    IcChat.clientsMap.keySet().stream().collect(Collectors.joining(","))); // 给客户端发送tab列表
                                Methods.printAbove(Methods.changeColor(
                                    name + "客户端(" + socket.getInetAddress() + ")验证通过", 
                                    Colors.GREEN_BOLD));
                            } else {
                                Methods.sendMessage(socket, "error", "name");
                                connecting = false;
                            }
                            continue;
                        }
                        pwdTimes--;
                        Map<String, Object> messageMap = new HashMap<>();
                        messageMap.put("type", "error");
                        messageMap.put("content", "password");
                        messageMap.put("number", pwdTimes);
                        Methods.sendMessage(socket, JSONUtil.toJsonStr(messageMap)); // 向客户端发送密码错误和剩余输入次数
                        sleep(100);
                        if (pwdTimes > 0) {
                            Methods.sendMessage(socket, "require", "password");
                        } else {
                            connecting = false;
                        }
                        break;
                    case "require":
                        if (content.equalsIgnoreCase("disconnect")) {
                            Methods.sendMessage(socket, "info", "disconnect");
                            connecting = false;
                            IcChat.clientsMap.remove(name);
                            Methods.printAbove(Methods.changeColor(
                                "与" + name + "客户端(" + socket.getInetAddress() + ")断开连接", 
                                Colors.YELLOW_BOLD));
                            continue;
                        }
                        break;

                    case "message":
                        Methods.broadcastMessage(
                            "<" + Methods.changeColor(this.name, Colors.BOLD) + "> " + content, 
                            Arrays.asList(name));
                        break;
                    case "tell":
                        String targetName = jsonObject.getStr("to");
                        if (!IcChat.clientsMap.containsKey(targetName)) {
                            Methods.sendMessage(socket, "error", "clientoffline");
                            continue;
                        }
                        String message = "<" + Methods.changeColor(name, Colors.BOLD) + ">" + Methods.changeColor("(私聊) ", Colors.PURPLE) + content;
                        Methods.sendMessage(
                            IcChat.clientsMap.get(targetName).getSocket(), 
                            "message", 
                            message);
                        break;
                    default:
                        Methods.sendMessage(socket, "info", "disconnect");
                        connecting = false;
                        Methods.printAbove(Methods.changeColor(
                            name + "客户端(" + socket.getInetAddress() + ")发送了一条非法消息，已与其断开连接", 
                            Colors.RED_BOLD));
                        break;
                }
            }
            shutdown();
        } catch (IOException e) {
            if (connecting) {
                Methods.printAbove(Methods.changeColor(
                    "与" + name + "客户端(" + socket.getInetAddress() + ")通信时出错", 
                    Colors.RED_BOLD));
                e.printStackTrace();
            }
        } catch (InterruptedException e) {
            Methods.printAbove(Methods.changeColor(
                "停止" + name + "客户端(" + socket.getInetAddress() + ")线程时出错", 
                Colors.RED_BOLD));
            e.printStackTrace();
        } catch (JSONException e) {
            Methods.printAbove(Methods.changeColor(
                name + "客户端(" + socket.getInetAddress() + ")发送了一条非法消息，已与其断开连接", 
                Colors.RED_BOLD));
            connecting = false;
            shutdown();
        } catch(Exception e) {
            IcChat.dynamicCompleter.setNameList(IcChat.clientsMap.keySet()); // 更新Tab列表
            Methods.sendMessage(
                socket, 
                "onlineList", 
                IcChat.clientsMap.keySet().stream().collect(Collectors.joining(","))); // 给客户端发送tab列表
        }
    }

    private void shutdown() {
        IcChat.dynamicCompleter.setNameList(IcChat.clientsMap.keySet()); // 更新Tab列表
        Methods.sendMessage(
            socket, 
            "onlineList", 
            IcChat.clientsMap.keySet().stream().collect(Collectors.joining(","))); // 给客户端发送tab列表
        if (socket.isClosed()) {
            return;
        }
        try { // 关闭连接
            socket.close();
        } catch (IOException e) {
            Methods.printAbove(Methods.changeColor(
                "关闭与" + name + "客户端(" + socket.getInetAddress() + ")的连接时出错", 
                Colors.RED_BOLD));
            e.printStackTrace();
        }
    }
}